#pragma once

#include <iostream>
#include <sys/types.h>     
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>
#include <string>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
#include "daemon.hpp"

const int defaultfd=-1;
const std::string& defaultip ="0.0.0.0";
const int backlog =10;//一般不要设置太大
enum{
    SOCKET_ERR=2,
    BIND_ERR=3,
    LISTEN_ERR=4,
};

class TcpServerd;

class ThreadData
{
public:
    ThreadData(int fd,const std::string& ip,const uint16_t& port,TcpServerd* t)
        :sockfd(fd)
        ,clientip(ip)
        ,clientport(port)
        ,tsvr(t)
        {}
public:
    int sockfd;
    std::string clientip;
    uint16_t clientport;
    TcpServerd* tsvr;
};

class TcpServerd
{
public:
    TcpServerd(const uint16_t port,const std::string& ip =defaultip)
        :_listensock(defaultfd)
        ,_port(port)
        ,_ip(defaultip)
    {}
    void InitServer()
    {
        //1.创建套接字TCP
        _listensock=socket(AF_INET,SOCK_STREAM,0);
        if(_listensock<0)
        {
            std::cout<<"socket create fail!"<<std::endl;
            exit(SOCKET_ERR);
        }
        std::cout<<"socket create succesfully!"<<std::endl;

        //2.配置信息   bind
        //2.1配置信息
        sockaddr_in local;
        bzero(&local,sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);
        inet_aton(_ip.c_str(),&(local.sin_addr));
        // local.sin_addr.s_addr=inet_addr(_ip.c_str());
        // local.sin_addr.s_addr=htonl(INADDR_ANY);
        //端口号用htons   IP用htonl
        //2.2bind
        int n = bind(_listensock,(sockaddr*)&local,sizeof(local));
        if(n<0)
        {
            std::cout<<"bind fail!"<<std::endl;
            exit(BIND_ERR);
        }
        std::cout<<"bind succesfully!"<<std::endl;


        //3.listen
        //TCP不同于UDP,TCP要确保稳定
        //Tcp是面向连接的,服务器是"被动的"
        //服务器需要一直处于一种,等待连接的状态
        int ret=listen(_listensock,backlog);
        if(ret<0)
        {
            std::cout<<"listen fail!"<<std::endl;
            exit(LISTEN_ERR);
        }
        std::cout<<"listen succesfully!"<<std::endl;

        

    }




    static void* Routine(void* args)
    {
        ThreadData* td=static_cast<ThreadData*> (args);
        pthread_detach(pthread_self());
        //让该线程分离,就不用阻塞join了
        //线程共享文件描述符表,不能随便关闭

        // Service(td->sockfd,td->clientip,td->clientport);
        //问题:静态成员函数,不能使用类内的其他成员函数
        td->tsvr->Service(td->sockfd,td->clientip,td->clientport);
        delete td;
        return nullptr;
    }





    void Start()
    {
        Daemon();
        std::cout<<"Tcpserver is runnning"<<std::endl;
        for(;;)
        {
        //1.获取新连接
        sockaddr_in client;
        socklen_t len=sizeof(client);
        int sockfd = accept(_listensock,(sockaddr*)&client,&len);
        //这才是真正进行通信的sock
        //之前的sock只是用来监听
        //监听  通信  是两个工作
        if(sockfd<0)
        {
            std::cout<<"accept fail!"<<std::endl;
            continue;
        }
        std::cout<<"get a new link...,sockfd: "<<sockfd<<std::endl;
        

        uint16_t clientport=ntohs(client.sin_port);//获取客户端端口
        char clientip[32];
        inet_ntop(AF_INET,&(client.sin_addr),clientip,sizeof(clientip));//获取客户端ip
        //2.根据新连接进行通信
        //version1--单进程
        // Service(sockfd,clientip,clientport);
        // close(sockfd);

        // //version2--多进程
        // pid_t id=fork();
        // if(id == 0)
        // {
        //     //子进程
        //     close(_listensock);
        //     if(fork()>0) exit(0);
        //     //子进程退出,让父进程回收
        //     //为什么?进程等待是阻塞等待,为了实现多进程的多链接,必须让父进程不阻塞
        //     //子进程退出,让孙子进程完成Service
        //     //子进程退出后,孙子进程被system接管,并且继续执行,自动清理,不会产生僵尸!
        //     //或者用信号,忽略信号,就不用回收了
        //     Service(sockfd,clientip,clientport);
        //     close(sockfd);
        //     exit(0);
        // }
        // //父进程
        // close(sockfd);
        // //service的工作是交给子进程进行的
        // //子进程已经拿到了sockfd
        // //为了避免父进程的文件描述符越来越多,关闭没用的sockfd
        // pid_t rid=waitpid(id,nullptr,0);

        //version3--多线程
        ThreadData* td=new ThreadData(sockfd,clientip,clientport,this);
        pthread_t tid;
        pthread_create(&tid,nullptr,Routine,td);
        

        //version4--线程池版本










        }
    }
    void Service(int sockfd , const std::string& clientip,const uint16_t& clientport)
    {
        char buffer[4096];
        while(true)
        {
            ssize_t n=read(sockfd,buffer,sizeof(buffer));
            //TCP是面向字节流的,read也是面向字节流的
            //从网络读取数据,本质就是从sockfd文件读取数据
            if(n>0)
            {
                buffer[n]=0;
                std::cout<<"client say# "<<buffer<<std::endl;
                std::string echo_string="tcpserver echo# ";
                echo_string += buffer;
                //回复//  发送数据
                write(sockfd,echo_string.c_str(),echo_string.size());
               
            }
            else if(n==0)
            {
                std::cout<<"断开连接"<<std::endl;
                break;
            }
            else
            {
                std::cout<<"读取出错"<<std::endl;
                break;
            }
            
        }
    }


    ~TcpServerd()
    {}
private:
    int _listensock;
    uint16_t _port;
    std::string _ip;
};